package com.example.generate.service;

import com.example.generate.domain.Generate;
import com.example.generate.domain.TableColumn;
import com.example.generate.mapper.GenerateMapper;
import com.google.common.base.CaseFormat;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Properties;

import static com.example.generate.utils.TextUtil.capitalizeFirstLetter;
import static com.example.generate.utils.TypeUtil.dataTypeToJavaType;

/**
 * 生成代码的核心服务
 * @author HTT
 */
@Service
public class GenerateService {

    @Resource
    private GenerateMapper generateMapper;

    @Value("${generate.url}")
    private String url;

    private void init(){
        Properties p = new Properties();
        // 加载classpath目录下的vm文件
        p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        // 定义字符集
        p.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
        // 初始化Velocity引擎，指定配置Properties
        Velocity.init(p);
    }

    /**
     * 指定表名生成代码
     * @param tableName
     */
    public void generate(String tableName) throws Exception {

        System.out.println("*****************CRUD代码开始生成...*****************");
        init();
        List<TableColumn> tableColumnList = generateMapper.selectByTableName(tableName);
        if(tableColumnList == null || tableColumnList.size() == 0){
            throw new Exception("表信息不存在！");
        }
        tableColumnList.stream()
                .forEach(tableColumn -> {
                    tableColumn.setJavaColumnName(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, tableColumn.getColumnName()));
                    tableColumn.setJavaType(dataTypeToJavaType(tableColumn.getDataType()));
                });
        Generate generate = new Generate();
        String primaryKey = tableColumnList.get(0).getColumnName();
        String keyType = tableColumnList.get(0).getJavaType();
        //表主键
        generate.setPrimaryKey(primaryKey);
        //表主键转驼峰
        generate.setJavaKey(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, primaryKey));
        //主键类型
        generate.setKeyType(keyType);
        //表名称
        generate.setTableName(tableName);
        //表名转驼峰
        generate.setJavaTableName(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, tableName));
        //实体类名字
        generate.setClassName(capitalizeFirstLetter(generate.getJavaTableName()));
        generate.setTableColumnList(tableColumnList);
        generateDomain(generate);
        generateService(generate);
        generateServiceImpl(generate);
        generateMapper(generate);
        generateXml(generate);
        System.out.println("*****************CRUD代码生成成功！*****************");
    }

    /**
     * 生成实体类
     * @param generate
     */
    private void generateDomain(Generate generate){
        Template template = Velocity.getTemplate("vm/java/domain.java.vm", "UTF-8");
        VelocityContext context = new VelocityContext();
        context.put("className",generate.getClassName());
        context.put("tableColumnList", generate.getTableColumnList());
        StringWriter writer = new StringWriter();
        template.merge(context, writer);
        save(writer,generate.getClassName()+".java");
    }

    /**
     * 生成Service文件
     */
    private void generateService(Generate generate){
        Template template = Velocity.getTemplate("vm/java/service.java.vm", "UTF-8");
        VelocityContext context = new VelocityContext();
        context.put("primaryKey",generate.getPrimaryKey());
        context.put("javaKey",generate.getJavaKey());
        context.put("keyType",generate.getKeyType());
        context.put("tableName",generate.getTableName());
        context.put("javaTableName",generate.getJavaTableName());
        context.put("className",generate.getClassName());
        StringWriter writer = new StringWriter();
        template.merge(context, writer);
        String fileName = generate.getClassName() + "Service.java";
        save(writer,fileName);
    }

    /**
     * 生成ServiceImpl文件
     */
    private void generateServiceImpl(Generate generate){
        Template template = Velocity.getTemplate("vm/java/serviceImpl.java.vm", "UTF-8");
        VelocityContext context = new VelocityContext();
        context.put("primaryKey",generate.getPrimaryKey());
        context.put("javaKey",generate.getJavaKey());
        context.put("keyType",generate.getKeyType());
        context.put("tableName",generate.getTableName());
        context.put("javaTableName",generate.getJavaTableName());
        context.put("className",generate.getClassName());
        StringWriter writer = new StringWriter();
        template.merge(context, writer);
        String fileName = generate.getClassName() + "ServiceImpl.java";
        save(writer,fileName);
    }

    /**
     * 生成Mapper文件
     */
    private void generateMapper(Generate generate){
        Template template = Velocity.getTemplate("vm/java/mapper.java.vm", "UTF-8");
        VelocityContext context = new VelocityContext();
        context.put("primaryKey",generate.getPrimaryKey());
        context.put("javaKey",generate.getJavaKey());
        context.put("keyType",generate.getKeyType());
        context.put("tableName",generate.getTableName());
        context.put("javaTableName",generate.getJavaTableName());
        context.put("className",generate.getClassName());
        StringWriter writer = new StringWriter();
        template.merge(context, writer);
        String fileName = generate.getClassName() + "Mapper.java";
        save(writer,fileName);
    }

    /**
     * 生成xml映射文件
     * @param generate
     */
    private void generateXml(Generate generate){
        Template template = Velocity.getTemplate("vm/java/mapper.xml.vm", "UTF-8");
        VelocityContext context = new VelocityContext();
        context.put("primaryKey",generate.getPrimaryKey());
        context.put("javaKey",generate.getJavaKey());
        context.put("tableName",generate.getTableName());
        context.put("className",generate.getClassName());
        context.put("tableColumnList", generate.getTableColumnList());
        StringWriter writer = new StringWriter();
        template.merge(context, writer);
        String fileName = generate.getClassName() + "Mapper.xml";
        save(writer,fileName);
    }

    /**
     * 保存为文件
     * @param writer
     * @param fileName
     */
    public void save(StringWriter writer,String fileName){

        String result = writer.toString();
        String filePath = url+fileName;
        FileWriter fileWriter = null;
        try {
            //获取文件名
            File file = new File(filePath);
            //文件夹不存在则新建
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            fileWriter = new FileWriter(filePath);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                fileWriter.write(result);
                fileWriter.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }

    }

}
